%!TEX program = xelatex
%!TEX encoding = UTF-8 Unicode

\documentclass[10pt,a4paper]{article} 

\usepackage{ctex} % 中文支持
\usepackage[top=2.5cm, bottom=2.5cm, left=2.5cm, right=2.5cm]{geometry} % 页边距
\usepackage{amsmath, amssymb} % 数学公式与符号
\usepackage{graphicx}
\usepackage{pythonhighlight}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 使表格美观
\usepackage{array}
\newcolumntype{M}[1]{>{\centering\arraybackslash}m{#1}}
%\newcolumntype{N}{@{}m{0pt}@{}}
\setlength\extrarowheight{3pt}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\usepackage{titling}
\setlength{\droptitle}{-2cm} % 标题上移

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\author{五六七 }
\title{美食推荐系统 }

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}

\maketitle

\begin{abstract}
根据顾客的消费记录，给顾客推荐一道美食。
\end{abstract}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%\setcounter{tocdepth}{2}
%\renewcommand\contentsname{目录}
%
%\renewcommand {\baselinestretch} {1.3}\normalsize 
%\tableofcontents 
%\renewcommand {\baselinestretch} {1.0}\normalsize

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{问题描述}
有一个风味美食平台，经营着多种不同风味的地方特色美食。在系统中维护着一个原始的打分表。
其中行表示各个顾客，列表示各种菜品。
每个顾客对消费某道菜品之后，都会打分，分数范围为1-5分，分数越高表示评价越高。
顾客还没消费的菜品，打分初始值为零分。
现在一共有11道菜品，一共有18位顾客的打分表。
问题是对这些顾客，对其尚未品尝的美食，进行打分估计。从而可以推荐打分估计最高的美食。

\begin{center}
\begin{table}[ht]\centering 
\caption{顾客消费打分表}\vspace{0.3cm}
\begin{tabular}{|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|}\hline 
&A1&A2&A3&A4&A5&A6&A7&A8&A9&A10&A11  \\ \hline 
&叉烧肠粉&新疆手抓饭&四川火锅&粤式烧鹅饭&大盘鸡拌面&东北饺子&重庆辣子鸡&广东虾饺&剁椒鱼头&兰州拉面&烤羊排 \\ \hline 
丁一&	5&	2&	1&	4&	0&	0&	2&	4&	0&	0&	0 \\ \hline 
刘二&	0&	0&	0&	0&	0&	0&	0&	0&	0&	3&	0 \\ \hline 
张三&	1&	0&	5&	2&	0&	0&	3&	0&	3&	0&	1 \\ \hline 
李四&	0&	5&	0&	0&	4&	0&	1&	0&	0&	0&	0 \\ \hline 
王五&	0&	0&	0&	0&	0&	4&	0&	0&	0&	4&	0 \\ \hline 
马六&	0&	0&	1&	0&	0&	0&	1&	0&	0&	5&	0 \\ \hline 
陈七&	5&	0&	2&	4&	2&	1&	0&	3&	0&	1&	0 \\ \hline 
胡八&	0&	4&	0&	0&	5&	4&	0&	0&	0&	0&	5 \\ \hline 
赵九&	0&	0&	0&	0&	0&	0&	4&	0&	4&	5&	0 \\ \hline 
钱十&	0&	0&	0&	4&	0&	0&	1&	5&	0&	0&	0 \\ \hline 
孙甲&	0&	0&	0&	0&	4&	5&	0&	0&	0&	0&	3 \\ \hline 
周乙&	4&	2&	1&	4&	0&	0&	2&	4&	0&	0&	0 \\ \hline 
吴丙&	0&	1&	4&	1&	2&	1&	5&	0&	5&	0&	0 \\ \hline 
郑丁&	0&	0&	0&	0&	0&	4&	0&	0&	0&	4&	0 \\ \hline 
冯戊&	2&	5&	0&	0&	4&	0&	0&	0&	0&	0&	0 \\ \hline 
储己&	5&	0&	0&	0&	0&	0&	0&	4&	2&	0&	0 \\ \hline 
魏庚&	0&	2&	4&	0&	4&	3&	4&	0&	0&	0&	0 \\ \hline 
高辛&	0&	3&	5&	1&	0&	0&	4&	1&	0&	0&	0 \\ \hline 
\end{tabular}
\end{table}
\end{center}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{建立模型}
一种思路是根据顾客已有的打分，计算菜品之间的相似程度。
然后任选一位顾客，使用菜品相似程度作为权重，来估计这位顾客对未消费菜品的可能打分。

%考虑顾客喜好的相似程度。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{菜品相似系数}
将打分表保存为一个矩阵。这是一个 $18\times 11$ 的矩阵。
\begin{eqnarray}
A=(a_{ij})_{18\times 11}=\begin{pmatrix} 
5&2&1&4&\cdots &0&0 \\ 
0&0&0&0&\cdots &3&0 \\ 
1&0&5&2&\cdots &0&1 \\ 
0&5&0&0&\cdots &0&0 \\ 
\vdots & \vdots & \vdots & \vdots & &\vdots & \vdots \\ 
0&2&4&0&\cdots &0&0 \\ 
0&3&5&1&\cdots &0&0 \\ 
\end{pmatrix}. 
\end{eqnarray}


然后计算列向量之间的相关系数。按定义，两个列向量
\begin{eqnarray}
\begin{pmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \\ \end{pmatrix}, 
\begin{pmatrix} y_1 \\ y_2 \\ \vdots \\ y_n \\ \end{pmatrix}
\end{eqnarray}
之间的皮尔逊相关系数为
\begin{eqnarray}
r = \frac{ \sum\limits_{k=1}^{n} (x_k-\bar{x})(y_k-\bar{y})}
{ \sqrt{\sum\limits_{k=1}^{n} (x_k-\bar{x})^2} \sqrt{\sum\limits_{k=1}^{n} (y_k-\bar{y})^2} }. 
\end{eqnarray}
其中 $\bar{x}$ 与 $\bar{y}$ 是这两个向量的所有分量的平均值，即
\begin{eqnarray}
\bar{x} = \frac{1}{n}\sum\limits_{k=1}^{n} x_k, \,\,\, 
\bar{y} = \frac{1}{n}\sum\limits_{k=1}^{n} y_k. 
\end{eqnarray}

设这个矩阵的11个列向量的两两之间的相关系数为 
\begin{eqnarray}
r_{ij}, \,\,\, i,j=1,2,\cdots, 11. 
\end{eqnarray}

两个列向量的皮尔逊相关系数的取值范围是 $-1\le r\le 1$. 但是我们希望菜品之间的相似程度的衡量取值范围为 $0\le s\le 1$. 于是作一个线性函数，将相关系数 $r$ 变换为相似程度 $s$, 公式取为 
\begin{eqnarray}
s_{ij} = \frac{1+r_{ij}}{2}, \,\,\, i,j=1,2,\cdots, 11. 
\end{eqnarray}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{某顾客未消费菜品的打分估计}
以第一位顾客丁一为例。这位顾客已经评价过的菜品编号为1,2,3,4,7,8, 打分分别为 5,2,1,4,2,4. 
现在我们想估计这位顾客对菜品5的打分。我们考虑菜品5与菜品1、菜品5与菜品2、菜品5与菜品3、菜品5与菜品4、菜品5与菜品7、菜品5与菜品8的相关系数，用这些相关系数作为权重，将这位顾客对菜品1、菜品2、菜品3、菜品4、菜品7、菜品8的已有的打分，计算加权平均。计算的公式为
\begin{eqnarray}
b_{1,5} = \frac{a_{1,1}s_{1,5} + a_{1,2}s_{2,5} + a_{1,3}s_{3,5} + a_{1,4}s_{4,5} + a_{1,7}s_{7,5} + a_{1,8}s_{8,5} }
{s_{1,5} + s_{2,5} +s_{3,5} +s_{4,5} +s_{7,5} +s_{8,5}}. 
\end{eqnarray}
其中 $a_{i,j}$ 是顾客 $i$ 对菜品 $j$ 的打分，$s_{i,j}$ 是菜品 $i$ 与菜品 $j$ 的相似程度。


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%\newpage 
\section{编程计算}

以第18位顾客高辛为例。这位顾客已经评价过的菜品编号为 2,3,4,7,8, 打分分别为 3,5,1,4,1. 
估计这位顾客对菜品1的打分为
\begin{eqnarray}
b_{18,1} = \frac{a_{18,2}s_{2,1} + a_{18,3}s_{3,1} + a_{18,4}s_{4,1} + a_{18,7}s_{7,1} + a_{18,8}s_{8,1} }
{s_{2,1} + s_{3,1} +s_{4,1} +s_{7,1} +s_{8,1} }. 
\end{eqnarray}


\begin{python}
import numpy as np
A=np.array([
[5,2,1,4,0,0,2,4,0,0,0],
[0,0,0,0,0,0,0,0,0,3,0],
[1,0,5,2,0,0,3,0,3,0,1],
[0,5,0,0,4,0,1,0,0,0,0],
[0,0,0,0,0,4,0,0,0,4,0],
[0,0,1,0,0,0,1,0,0,5,0],
[5,0,2,4,2,1,0,3,0,1,0],
[0,4,0,0,5,4,0,0,0,0,5],
[0,0,0,0,0,0,4,0,4,5,0],
[0,0,0,4,0,0,1,5,0,0,0],
[0,0,0,0,4,5,0,0,0,0,3],
[4,2,1,4,0,0,2,4,0,0,0],
[0,1,4,1,2,1,5,0,5,0,0],
[0,0,0,0,0,4,0,0,0,4,0],
[2,5,0,0,4,0,0,0,0,0,0],
[5,0,0,0,0,0,0,4,2,0,0],
[0,2,4,0,4,3,4,0,0,0,0],
[0,3,5,1,0,0,4,1,0,0,0]])
\end{python}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{python}
#np.set_printoptions(precision=2, suppress=True)   
# 设置显示三位小数点，并且不用科学计数法显示

M=np.mean(A,axis=0)
C=A-M
R=np.zeros([11,11])
for i in range(11):
    for j in range(11):
        num = np.sum(C[:,i]*C[:,j])
        denom = np.sqrt(np.sum(C[:,i]**2))*np.sqrt(np.sum(C[:,j]**2))
        R[i,j] = num/denom

R2=np.corrcoef(A)
S=(R+1)/2
#print(R)
\end{python}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{python}
b_17_0_num = A[17,1]*S[1,0]+ A[17,2]*S[2,0] + \
    A[17,3]*S[3,0]+ A[17,6]*S[6,0]+ A[17,7]*S[7,0]
b_17_0_denom = S[1,0]+S[2,0]+S[3,0]+S[6,0]+S[7,0]
b_17_0 = b_17_0_num/b_17_0_denom
print('对高辛推荐菜品1的打分估计为：%.2f'%b_17_0)
# 高辛已评菜品：1,2,3,6,7, 未评菜品：0,4,5,8,9,10
\end{python}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{python}
for k in (0,4,5,8,9,10):
    b_17_k_num = A[17,1]*S[1,k]+ A[17,2]*S[2,k] + \
        A[17,3]*S[3,k]+ A[17,6]*S[6,k]+ A[17,7]*S[7,k]
    b_17_k_denom = S[1,k]+S[2,k]+S[3,k]+S[6,k]+S[7,k]
    b_17_k = b_17_k_num/b_17_k_denom
    print('对高辛推荐菜品%d的打分估计为：%.2f.'%(k,b_17_k))

print('\n')
\end{python}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{python}
TupleA=(1,2,3,6,7)
TupleB=(0,4,5,8,9,10)

for k in TupleB:
    b_17_num=0
    b_17_denom=0
    for m in TupleA:
        b_17_num=b_17_num + A[17,m]*S[m,k]
        b_17_denom=b_17_denom + S[m,k]
    b_17 = b_17_num/b_17_denom
    print('对高辛推荐菜品%d的打分估计为：%.2f.'%(k,b_17))
\end{python}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{回答问题}

高辛对未曾品尝的其余菜品的打分的估计为

\begin{center}
\begin{table}[ht]\centering 
\caption{高辛打分的预测}\vspace{0.3cm}
\begin{tabular}{|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|M{0.8cm}|}\hline 
菜品 &0 &4 &5 &8 &9 &10  \\ \hline 
打分 &2.35 &3.03 &2.97 &3.15 &2.90 &2.85  \\ \hline 
\end{tabular}
\end{table}
\end{center}

%对高辛推荐菜品0的打分估计为：2.35.
%对高辛推荐菜品4的打分估计为：3.03.
%对高辛推荐菜品5的打分估计为：2.97.
%对高辛推荐菜品8的打分估计为：3.15.
%对高辛推荐菜品9的打分估计为：2.90.
%对高辛推荐菜品10的打分估计为：2.85.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{练习题}

\begin{enumerate}%\itemsep0.5em 

\item  手工计算下述两个数据向量的相关系数，并写程序计算验证。
\begin{python}
x=[3, 0, 2, 3, 0, 3, 2, 2, 4, 0]
y=[1, 0, 0, 0, 4, 3, 0, 3, 1, 0]
\end{python}


\end{enumerate}



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%\section{参考文献 }
\begin{thebibliography}{99}
\bibitem{sishoukui-2} 司守奎,孙玺菁. \emph{Python数学建模算法与应用}, 国防工业出版社. 2022年1月第1版. 
%\bibitem{rosen-dm6}Kenneth H. Rosen 著, 袁崇义, 屈婉玲, 张桂芸等译. \emph{离散数学及其应用}, 机械工业出版社，2013年4月第1版。
\end{thebibliography}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\end{document}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

